package br.com.unifebe.tcc.componente.GUI;


import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.io.Serializable;


import javax.swing.event.TableModelEvent;
import javax.swing.table.AbstractTableModel;

public class TableModel <E extends Object> extends AbstractTableModel implements Serializable{

	protected ArrayList    dataList;
	protected ArrayList    columnIdentifiers;
	private ArrayList<E> lista;

	public boolean addObjeto( E o){
		if(lista == null){
			lista = new ArrayList<E>();
		}
		return lista.add(o);
	}
	public boolean setLista( Collection<E> o){
		if(lista == null){
			lista = new ArrayList<E>();
		}
		return lista.addAll(o); 
	}
	
	public List<E> getLista(){
		if(lista == null){
			lista = new ArrayList<E>();
		}
		return lista;
	}
	
	public E getRow(int row){
		ArrayList<E> t = (ArrayList<E>)getLista();
		return t.get(row);
	}
	
	public TableModel() {
		this(0, 0);
	}
	
	private static ArrayList newLista(int size) {
		ArrayList c = new ArrayList(size);
		return c;
	}


	public TableModel(int rowCount, int columnCount) {
		this(newLista(columnCount), rowCount);
	}


	public TableModel(ArrayList columnNames, int rowCount) {
		setDataVector(newLista(rowCount), columnNames);
	}


	public TableModel(Object[] columnNames, int rowCount) {
		this(convertToArray(columnNames), rowCount);
	}



	public TableModel(ArrayList data, ArrayList columnNames) {
		setDataVector(data, columnNames);
	}

	public TableModel(Object[][] data, Object[] columnNames) {
		setDataVector(data, columnNames);
	}


	public TableModel(String[] data, String[] columnNames) {
		setDataVector(data, columnNames);
	}
	public Collection getDataVector() {
		return dataList;
	}

	private static ArrayList nonNullVector(ArrayList v) {
		return (v != null) ? v : new ArrayList();
	}


	public void setDataVector(ArrayList dataList, ArrayList columnIdentifiers) {
		this.dataList = nonNullVector(dataList);
		this.columnIdentifiers = nonNullVector(columnIdentifiers);
		justifyRows(0, getRowCount());
		fireTableStructureChanged();
	}


	public void setDataVector(Object[][] dataVector, Object[] columnIdentifiers) {
		setDataVector(convertToArray(dataVector), convertToArray(columnIdentifiers));
	}

	public void setDataVector(Object[] dataVector, Object[] columnIdentifiers) {
		setDataVector(convertToArray(dataVector), convertToArray(columnIdentifiers));
	}
	
	public void newDataAvailable(TableModelEvent event) {
		fireTableChanged(event);
	}


	private void justifyRows(int from, int to) {

		//dataList.setSize(getRowCount());

		for (int i = from; i < to; i++) {
			if (dataList.get(i) == null) {
				dataList.add(i,new ArrayList() );
			}
			//((ArrayList)dataList.get(i)).get(getColumnCount());
		}
	}


	public void newRowsAdded(TableModelEvent e) {
		justifyRows(e.getFirstRow(), e.getLastRow() + 1);
		fireTableChanged(e);
	}

	public void rowsRemoved(TableModelEvent event) {
		fireTableChanged(event);
	}


	public void setNumRows(int rowCount) {
		int old = getRowCount();
		if (old == rowCount) {
			return;
		}
		//dataList.setSize(rowCount);
		if (rowCount <= old) {
			fireTableRowsDeleted(rowCount, old-1);
		}
		else {
			justifyRows(old, rowCount);
			fireTableRowsInserted(old, rowCount-1);
		}
	}

	public void setRowCount(int rowCount) {
		setNumRows(rowCount);
	}


	public void addRow(Collection rowData) {
		insertRow(getRowCount(), rowData);
	}


	public void addRow(Object[] rowData) {
		addRow(convertToArray(rowData));
	}



	public void insertRow(int row, Collection rowData) {
		dataList.add(row, rowData);
		justifyRows(row, row+1);
		fireTableRowsInserted(row, row);
	}


	public void insertRow(int row, Object[] rowData) {
		insertRow(row, convertToArray(rowData));
	}

	private static int gcd(int i, int j) {
		return (j == 0) ? i : gcd(j, i%j);
	}

	private static void rotate(ArrayList v, int a, int b, int shift) {
		int size = b - a;
		int r = size - shift;
		int g = gcd(size, r);
		for(int i = 0; i < g; i++) {
			int to = i;
			Object tmp = v.get(a + to);
			for(int from = (to + r) % size; from != i; from = (to + r) % size) {
				v.add(a + to, v.get(a + from));
				to = from;
			}
			v.add( a + to,tmp);
		}
	}


	public void moveRow(int start, int end, int to) {
		int shift = to - start;
		int first, last;
		if (shift < 0) {
			first = to;
			last = end;
		}
		else {
			first = start;
			last = to + end - start;
		}
		rotate(dataList, first, last + 1, shift);

		fireTableRowsUpdated(first, last);
	}

	public void removeRow(int row) {
		dataList.remove(row);
		fireTableRowsDeleted(row, row);
	}

	public void setColumnIdentifiers(ArrayList columnIdentifiers) {
		setDataVector(dataList, columnIdentifiers);
	}


	public void setColumnIdentifiers(Object[] newIdentifiers) {
		setColumnIdentifiers(convertToArray(newIdentifiers));
	}


	public void setColumnCount(int columnCount) {
		//columnIdentifiers.setSize(columnCount);
		justifyRows(0, getRowCount());
		fireTableStructureChanged();
	}

	public void addColumn(Object columnName) {
		addColumn(columnName, (ArrayList)null);
	}


	public void addColumn(Object columnName, ArrayList columnData) {
		columnIdentifiers.add(columnName);
		if (columnData != null) {
			int columnSize = columnData.size();
			//  if (columnSize > getRowCount()) {
			//    dataList.size(columnSize);
			// }
			justifyRows(0, getRowCount());
			int newColumn = getColumnCount() - 1;
			for(int i = 0; i < columnSize; i++) {
				ArrayList row = (ArrayList)dataList.get(i);
				row.add( newColumn, columnData.get(i));
			}
		}
		else {
			justifyRows(0, getRowCount());
		}

		fireTableStructureChanged();
	}


	public void addColumn(Object columnName, Object[] columnData) {
		addColumn(columnName, convertToArray(columnData));
	}

	//
	// Implementing the TableModel interface
	//

	/**
	 * Returns the number of rows in this data table.
	 * @return the number of rows in the model
	 */
	@Override
	public int getRowCount() {
		return dataList.size();
	}


	@Override
	public int getColumnCount() {
		return columnIdentifiers.size();
	}


	@Override
	public String getColumnName(int column) {
		Object id = null;
		// This test is to cover the case when
		// getColumnCount has been subclassed by mistake ...
		if (column < columnIdentifiers.size() && (column >= 0)) {
			id = columnIdentifiers.get(column);
		}
		return (id == null) ? super.getColumnName(column)
				: id.toString();
	}


	@Override
	public boolean isCellEditable(int row, int column) {
		return false;
	}


	@Override
	public Object getValueAt(int row, int column) {
		ArrayList rowVector = (ArrayList)dataList.get(row);
		return rowVector.get(column);
	}


	@Override
	public void setValueAt(Object valor, int row, int column) {
		ArrayList rowVector = (ArrayList)dataList.get(row);
		rowVector.add(column,valor);
		fireTableCellUpdated(row, column);
	}

	//
	// Protected Methods
	//

	protected static ArrayList convertToArray(Object[] anArray) {
		if (anArray == null) {
			return null;
		}
		ArrayList v = new ArrayList(anArray.length);
		for (int i=0; i < anArray.length; i++) {
			v.add(anArray[i]);
		}
		return v;
	}


	protected static ArrayList convertToArray(Object[][] anArray) {
		if (anArray == null) {
			return null;
		}
		ArrayList v = new ArrayList(anArray.length);
		for (int i=0; i < anArray.length; i++) {
			v.add(convertToArray(anArray[i]));
		}
		return v;
	}
}
